package com.crawler.util.contex;

import com.crawler.util.template.MatchResult;
import com.crawler.util.template.URLTemplate;
import com.crawler.util.template.URLTemplateBuilder;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;
import net.sf.ehcache.search.expression.EqualTo;

import java.util.*;

/**
 * 基于ehcache，对正文提取表达式进行缓存
 *
 * @author guor
 */
public class ContexCacheProvider {
    private final Cache cache;

    private ContexCacheProvider(List<Contex> list) {
        this.cache = CacheManager.create().getCache("contex");
        if (list != null && !list.isEmpty()) {
            for (Contex contex : list) {
                cache.put(new Element(contex.getId(), contex));
            }
        }
    }

    public String extract(String url, String html) {
        Contex contex = getBestMatchContex(url);
        if (contex == null) {
            return null;
        }
        return ContentExtractorFactory.create(contex.getExpression()).extract(html);
    }

    public Contex getBestMatchContex(String url) {
        URLTemplate template = URLTemplateBuilder.build(url);
        Contex contex = findByTemplate(template.toString());
        if (contex != null) {
            return contex;
        }
        List<Contex> list = findByHostAndDoctype(template.getHost(), template.getDoctype());
        if (!list.isEmpty()) {
            List<MatchResult> resultList = new ArrayList<>(list.size());
            Map<String, Contex> contexMap = new HashMap<>(list.size());
            for (Contex c : list) {
                MatchResult matchResult = URLTemplateBuilder.compile(c.getTemplate()).match(url);
                if (matchResult.isNotMatch()) {
                    continue;
                }
                resultList.add(matchResult);
                contexMap.put(matchResult.getMatchTemplate().toString(), c);
            }
            if (resultList.isEmpty()) {
                return null;
            }
            Collections.sort(resultList);
            MatchResult matchResult = resultList.get(0);
            if (matchResult.isNotMatch()) {
                return null;
            }
            return contexMap.get(resultList.get(0).getMatchTemplate().toString());
        }
        return null;
    }

    private List<Contex> findByHostAndDoctype(String host, String doctype) {
        List<Contex> list = new ArrayList<>();
        Results results = cache.createQuery().includeValues().addCriteria(new EqualTo("host", host)).addCriteria(new EqualTo("doctype", doctype)).execute();
        if (results.hasValues()) {
            List<Result> resultList = results.all();
            for (Result result : resultList) {
                list.add((Contex) result.getValue());
            }
        }
        return list;
    }

    public Contex findByTemplate(final String template) {
        Results results = cache.createQuery().includeValues().addCriteria(new EqualTo("template", template)).execute();
        if (results.hasValues()) {
            return (Contex) results.all().get(0).getValue();
        }
        return null;
    }
}
